package org.example.consultant.config;

import dev.langchain4j.community.store.embedding.redis.RedisEmbeddingStore;
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.DocumentSplitter;
import dev.langchain4j.data.document.loader.ClassPathDocumentLoader;
import dev.langchain4j.data.document.loader.FileSystemDocumentLoader;
import dev.langchain4j.data.document.parser.apache.pdfbox.ApachePdfBoxDocumentParser;
import dev.langchain4j.data.document.splitter.DocumentSplitters;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.memory.chat.ChatMemoryProvider;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.rag.content.retriever.ContentRetriever;
import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.EmbeddingStoreIngestor;
import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
import dev.langchain4j.store.memory.chat.ChatMemoryStore;
import dev.langchain4j.store.memory.chat.InMemoryChatMemoryStore;
import org.example.consultant.aiservice.ConsultantService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.List;

@Configuration
public class CommonConfig {

    @Autowired
    private OpenAiChatModel model;

    @Autowired
    private ChatMemoryStore redisChatMemoryStore;

    @Autowired
    private EmbeddingModel embeddingModel;

    @Autowired
    private RedisEmbeddingStore redisEmbeddingStore;

//    @Bean
//    public ConsultantService consultantService(){
//        ConsultantService consultantService = AiServices.builder(ConsultantService.class)
//                .chatModel(model)
//                .build();
//        return consultantService;
//
//    }

    //构建会话记忆对象
    @Bean
    public ChatMemory chatMemory(){
        MessageWindowChatMemory memory = MessageWindowChatMemory.builder()
                .maxMessages(20) //存储会话的最大数量
                .build();
        return memory;

    }

    //构建chatMemoryProvider对象
    @Bean
    public ChatMemoryProvider chatMemoryProvider(){
        ChatMemoryProvider chatMemoryProvider = new ChatMemoryProvider() {
            @Override
            public ChatMemory get(Object memoryId) {
               return MessageWindowChatMemory.builder()
                       .id(memoryId) //传入id，如果没有这生成一个新id
                       .maxMessages(20)
                       .chatMemoryStore(redisChatMemoryStore)
                       .build();
            }
        };
        return chatMemoryProvider;
    }

    //构建向量数据库操作对象
    //@Bean //当注入了redisearch后就没有必要每次都在启动时注入Bean
    public EmbeddingStore store(){ //embeddingStore在依赖包中一存在，不能重复命名,所以使用store
        //1.加载文档进内存
        //List<Document> documents = FileSystemDocumentLoader.loadDocuments("D:\\myProject\\consultant\\src\\main\\resources\\content");
        //List<Document> documents = ClassPathDocumentLoader.loadDocuments("content");
        List<Document> documents = ClassPathDocumentLoader.loadDocuments("content",new ApachePdfBoxDocumentParser());
        //2.构建向量数据库操作对象 操作的时内存版本的向量数据库
        //InMemoryEmbeddingStore store = new InMemoryEmbeddingStore();


        //构建文档分割器对象(每个片段最大容纳的字符,两个片段之间重叠字符的个数)
        DocumentSplitter ds = DocumentSplitters.recursive(500,100);

                //3.构建一个EmbeddingStoreIngestor对象，完成文本数据切割，向量话，存储
        EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
               // .embeddingStore(store)
                .embeddingStore(redisEmbeddingStore)
                .documentSplitter(ds)
                .embeddingModel(embeddingModel) //配置向量模型
                .build();
        ingestor.ingest(documents);
        return redisEmbeddingStore;
    }



    //构建向量数据库检索对象
    @Bean
    public ContentRetriever contentRetriever(/*EmbeddingStore store*/){
        return EmbeddingStoreContentRetriever.builder()
                .embeddingStore(redisEmbeddingStore)
                .minScore(0.5) //最小的余弦相似度值
                .maxResults(3) //设置最大的查询获取数量
                .embeddingModel(embeddingModel)
                .build();
    }
}


